<template>
  <div class="x-table">
    <div class="x-table-filter tools_bar" v-if="showSearch">
      <a-form layout="inline">
        <a-form-item
          v-for="item in filterArray"
          :key="item.attr"
          :label="item.label"
        >
          <slot :name="item.attr" :data="item" v-if="item.slot"></slot>
          <template v-else>
            <a-input
              v-model:value="formInfo[item.attr]"
              :placeholder="item.placeholder"
              v-if="item.type == 'input'"
              @change="(val:string) => propChange(val, item)"
            />
            <a-range-picker
              v-model:value="formInfo[item.attr]"
              v-if="item.type == 'timeRange'"
              :show-time="item.showTime ? item.showTime : false"
              :valueFormat="item.format || 'YYYY-MM-DD'"
              :placeholder="item.placeholder"
              @change="(val:string,dateString:string) => propChange(dateString, item)"
            />
            <a-date-picker
              :show-time="item.showTime ? item.showTime : false"
              style="width: 178px"
              v-model:value="formInfo[item.attr]"
              v-if="item.type == 'time'"
              :format="item.format || 'YYYY-MM-DD'"
              :placeholder="item.placeholder"
              @change="(val:string,dateString:string) => propChange(dateString, item)"
            />
            <a-select
              style="width: 178px"
              :placeholder="item.placeholder"
              v-model:value="formInfo[item.attr]"
              v-if="item.type == 'select'"
              @change="(val:string) => propChange(val, item)"
            >
              <template v-if="item.options && item.options.length > 0">
                <a-select-option
                  :title="oitem.name"
                  :value="oitem.value"
                  v-for="oitem in item.options"
                  :key="oitem.value"
                  >{{ oitem.name }}</a-select-option
                >
              </template>
            </a-select>
          </template>
        </a-form-item>
        <a-form-item>
          <a-space>
            <a-button type="primary" @click="showMore" v-if="showLimit">
              <template #icon>
                <DownOutlined v-if="toggleLimit" />
                <UpOutlined v-else></UpOutlined>
              </template>
              {{ toggleLimit ? "展开更多" : "收起" }}</a-button
            >
            <a-button @click="reset">重置</a-button>
            <a-button type="primary" @click="search">查询</a-button>
            <slot name="btn"></slot>
          </a-space>
        </a-form-item>
      </a-form>
    </div>
    <div class="x-table-list" ref="tableRef">
      <a-spin :spinning="isLoading" tip="正在加载...">
        <slot name="myTable" :data="list" :res="response" :tableH="tableHeight">
        </slot>
      </a-spin>
    </div>
    <div class="x-table-footer tools_bar" v-if="showPage">
      <a-pagination
        :show-size-changer="showSizeChange"
        v-model:current="pageIndex"
        v-model:pageSize="pageSize"
        :total="total"
        :show-total="(total:string) => `共 ${total} 条`"
        @change="indexChange"
      />
    </div>
  </div>
</template>
<script lang="ts">
export default {
  name: "x-table",
};
</script>
<script setup lang="ts">
import { dealForm, type SearchProp } from ".";
import {
  ref,
  reactive,
  onMounted,
  watch,
  getCurrentInstance,
  computed,
  nextTick,
} from "vue";
import { DownOutlined, UpOutlined } from "@ant-design/icons-vue";
import type { PropType } from "vue";
import { useRoute, useRouter } from "vue-router";
import dayjs from "dayjs";

import { config } from "../config";

const props = defineProps({
  reqParams: {
    type: Function,
    default: (search: any) => {
      return search;
    },
  },
  req: {
    type: Function,
    required: true,
  },
  showSizeChange: {
    type: Boolean,
    default: true,
  },
  // 是否展示分页
  showPage: {
    type: Boolean,
    default: true,
  },
  // 是否展示搜索条件
  showSearch: {
    type: Boolean,
    default: true,
  },
  filterDict: {
    type: Array as PropType<Array<SearchProp>>,
  },
  dealList: {
    type: Function,
    default: (data: Array<any>) => data,
  },
  limit: {
    type: Number,
    default: 2,
  },
  searchInit: {
    type: Function,
  },
  showLimit: {
    type: Boolean,
    default: true,
  },
  resetKeys: {
    type: Array,
    default: () => [],
  },
  dealResponse: {
    type: Function,
  },
});
const isLoading = ref(false);
const list = ref([]);
const tableRef = ref<HTMLElement>();
const response = ref({});
const total = ref(0);
const route = useRoute();
const router = useRouter();
const query = route.query;
const toggleLimit = ref(props.showLimit);
const tableHeight = ref(0); // 表格的高度包括表头和分页
const pageSize = ref(
  Number(query.size) || Number(window.localStorage.getItem("PAGESIZE")) || 10
);
const filterArray = computed(() => {
  if (props.showSearch) {
    const temp = props.filterDict;
    if (props.showLimit) {
      if (toggleLimit.value) {
        return temp.slice(0, props.limit);
      }
    }
    return temp;
  }
  return [];
});
const showMore = () => {
  toggleLimit.value = !toggleLimit.value;
};

const pageIndex = ref(query.page ? Number(query.page) : 1);
const path = route.path;
const formInfo = reactive<any>({});
let oldPage = 10;
const search = () => {
  const form = dealForm(formInfo);
  form.timestamp = new Date().getTime();
  pushPage(form);
};
const reset = () => {
  const keys = Object.keys(formInfo);
  keys.forEach((k) => {
    if (!props.resetKeys.includes(k)) {
      formInfo[k] = undefined;
    }
  });
  pushPage(formInfo);
};
const setTableHeight = () => {
  const he = tableRef.value?.clientHeight || 0;
  if (props.showPage) {
    tableHeight.value = he - 70;
  } else {
    tableHeight.value = he - 20;
  }
};
const propChange = (val: string, item: any) => {
  // console.log(item);
  if (item.type == "select") {
    search();
    // pushPage(formInfo.value);
  }
};
const fetchData = async () => {
  
  const searchParams = {
    ...route.query,
    size: pageSize.value,
    page: pageIndex.value,
  };
  const params = props.reqParams(
    JSON.parse(JSON.stringify(config.dealTableSearch(searchParams)))
  );
  if (params === false) {
    return;
  }
  isLoading.value = true;

  const res = await props.req(params);
  if (res.success) {
    response.value = res;
    if (pageIndex.value == 1 || !pageIndex.value) {
      list.value = [];
    }
    // console.log("=========");
    // console.log(config);
    let tableres: any = {};
    if (props.dealResponse) {
      tableres = props.dealResponse(res);
    } else if (config.dealTableRes) {
      tableres = config.dealTableRes(res);
    }
    if (props.showPage) {
      total.value = tableres.total;
    }

    list.value = props.dealList(tableres.list);
  }
  isLoading.value = false;
  nextTick(() => {
    setTableHeight();
  });
};
watch(
  () => route.fullPath,
  async (nv, ov) => {
    const nvPath = nv.split("?")[0];
    const ovPath = ov.split("?")[0];
    if (nvPath == ovPath) {
      fetchData();
    }
  }
);

const pushPage = (search: any) => {
  router.push({
    path,
    query: search,
  });
};

const indexChange = (val: number, pSize: number) => {
  if (oldPage != pSize) {
    pageIndex.value = 1;
  }
  oldPage = pSize;
  pushPage({
    ...route.query,
    page: pageIndex.value,
    size: pageSize.value,
  });
};

const setInitSearchForm = (temp, queryParams) => {
  const searchParams = JSON.parse(JSON.stringify(queryParams));
  if (temp) {
    for (let i = 0; i < temp?.length; i++) {
      const item = temp[i];
      if (item.type == "time" && searchParams[item.attr]) {
        formInfo[item.attr] = dayjs(searchParams[item.attr]);
      } else if (item.type == "timeRange" && searchParams[item.attr]) {
        const [first, second] = searchParams[item.attr];
        formInfo[item.attr] = [
          dayjs(first).format(item.format),
          dayjs(second).format(item.format),
        ];
      } else {
        formInfo[item.attr] = searchParams[item.attr];
      }
    }
  }
};

const initSearch = async () => {
  const temp = filterArray.value;
  const searchParams = JSON.parse(JSON.stringify(query));
  if (temp) {
    for (let i = 0; i < temp?.length; i++) {
      const item = temp[i];
      if (temp[i].options && temp[i].fun) {
        temp[i].options = await temp[i]["fun"]?.();
      }
      if (item.type == "time" && searchParams[item.attr]) {
        formInfo[item.attr] = dayjs(searchParams[item.attr]);
      } else if (item.type == "timeRange" && searchParams[item.attr]) {
        const [first, second] = searchParams[item.attr];
        formInfo[item.attr] = [
          dayjs(first).format(item.format),
          dayjs(second).format(item.format),
        ];
      } else {
        formInfo[item.attr] = searchParams[item.attr];
      }
    }
  }
  if (props.searchInit) {
    props.searchInit(temp);
  }
};

onMounted(() => {
  initSearch();
  if (!props.searchInit) {
    fetchData();
  }

  setTableHeight();
});

defineExpose({
  fetchData,
  setInitSearchForm,
});
</script>
<style lang="scss">
.x-table {
  display: flex;
  flex-direction: column;
  height: 100%;
  .tools_bar {
    background-color: #eef1f6;
    padding: 8px 8px 0;
    box-sizing: border-box;
  }
  .x-table-filter {
    .ant-form-item {
      padding-bottom: 8px;
    }
  }
  .x-table-list {
    flex: 1;
    .ant-spin-nested-loading {
      height: 100%;
    }
    .ant-spin-container,
    .ant-table-wrapper,
    .ant-table-container,
    .ant-table-content,
    .ant-table {
      height: 100%;
    }
    .ant-table-content table {
      height: 100%;
    }
    .ant-spin-spinning {
      height: 600px;
      width: 100%;
      display: flex;
      justify-content: center;
      align-items: center;
    }
  }
  .x-table-footer {
    flex: 0 0 54px;
    display: flex;
    align-items: center;
    padding: 0;
    justify-content: center;
  }
}
</style>
